<?php
/** 
 * @brief Elasticsearch操作类 
 */
class Es {
    // Elasticsearch客户端实例
    private $client;

    // 构造函数
    public function __construct() {
        $config = \Yaf_Registry::get('Config');
        $params = [
            $config->elasticsearch->host . ':' . $config->elasticsearch->port
        ];
        $this->client = \Elasticsearch\ClientBuilder::create()->setHosts($params)->build();
    }
 
    // 创建索引
    public function createIndex($index, $properties = [], $settings = []) {
        if ($this->hasIndex($index)) {
            $this->deleteIndex($index);
        }

        $params  = [
            'index' => $index
        ];
        if (empty($settings)) {
            $settings = [
                'number_of_shards' => 5,
                'number_of_replicas' => 0
            ];
        }
        $params['body']['settings'] = $settings;
        if (!empty($properties)) {
            $params['body']['mappings'] = [
                '_source' => [
                    'enabled' => true
                ],
                'properties' => $properties
            ];
        }
        return $this->client->indices()->create($params);
    }

    // 判断索引是否存在
    public function hasIndex($index) {
        $params = [
            'index' => $index
        ];
        return $this->client->indices()->exists($params);
    }
    
    // 删除索引
    public function deleteIndex($index) {
        $params  = [
            'index' => $index
        ];
        return $this->client->indices()->delete($params);
    }

    // 添加单一文档
    public function addDoc($index, $doc, $id = null) {
        $params = [
            'index' => $index,
            'body' => $doc
        ];
        if (null !== $id) $params['id'] = $id;
        return $this->client->index($params);
    }
    
    // 批量添加文档
    public function bulkDoc($index, $docs) {
        $params = ['body' => []];
        $total = 0;
        foreach ($docs as $i => $item) {
            if (!isset($item['id']) || empty($item['id'])) {
                continue;
            }
            $params['body'][] = [
                'index' => [
                    '_index' => $index,
                    '_id' => $item['id']
                ]
            ];
            unset($item['id']);
            $params['body'][] = $item;
            if ($i % 1000 == 0) {
                $responses = $this->client->bulk($params);
                $params = ['body' => []];
                unset($responses);
            }
            $total++;
        }
        if (!empty($params['body'])) {
            $this->client->bulk($params);
        }
        return $total;
    }

    // 判断文档是否存在
    public function hasDoc($index, $id) {
        $params = [
            'index' => $index,
            'id' => $id
        ];
        return $this->client->exists($params);
    }

    // 获取单一文档
    public function getDoc($index, $id) {
        $params = [
            'index' => $index,
            'id' => $id
        ];
        return $this->client->get($params);
    }

    // 获取多个文档
    public function getDocs($index, $ids) {
        $params = [
            'index' => $index,
            'body' => [
                'ids' => $ids
            ]
        ];
        return $this->client->mget($params);
    }

    // 更新单一文档
    public function updateDoc($index, $id, $doc) {
        $params = [
            'index' => $index,
            'id' => $id,
            'body' => [
                'doc' => $doc
            ]
        ];
        return $this->client->update($params);
    }

    // 删除单一文档
    public function deleteDoc($index, $id) {
        $params = [
            'index' => $index,
            'id' => $id
        ];
        return $this->client->delete($params);
    }

    // 设置映射
    public function putMapping($index, $properties) {
        $params = [
            'index' => $index,
            'body' => [
                '_source' => [
                    'enabled' => true
                ],
                'properties' => $properties
            ]
        ];
        return $this->client->indices()->putMapping($params);
    }

    // 获取映射
    public function getMapping($index) {
        $params = [
            'index' => $index
        ];
        return $this->client->indices()->getMapping($params);
    }

    // 搜索文档
    public function search($index, $query = [], $page = 1, $size = 10, $sort = []) {
        $params = [
            'index' => $index,
            'body'  => [
                'query' => $query,
                'sort' => $sort,
                'from' => ($page - 1) * $size,
                'size' => $size
            ]
        ];
        return $this->client->search($params);
    }
}
